﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Irony.Parsing;
using Microsoft.VisualStudio.TextManager.Interop;
using LuaLanguage.Integration;

namespace LuaLanguage
{
    public static class LuaEditorUtilities
    {
        public static int SortMatches(BraceMatch b1, BraceMatch b2)
        {
            return b2.Priority.CompareTo(b1.Priority);
        }

        public static List<HiddenRegion> GetHiddenRegions(ParseTreeNode root)
        {
            var regions = new List<HiddenRegion>();
            FindHiddenRegions(root, ref regions);      
            return regions;
        }

        static void FindHiddenRegions(Irony.Parsing.ParseTreeNode root, ref List<HiddenRegion> regions)
        {
            if (root == null || root.ChildNodes == null)
                return; 

            foreach (var child in root.ChildNodes)
            {
                Irony.Parsing.Token startToken = null;
                Irony.Parsing.Token endToken = null;
                int startOffset = 0;

                if (child.Term.Name == "table constructor")
                {
                    startToken = child.FirstChild.Token;    // '{' symbol
                    endToken = child.LastChild.Token;       // '}' symbol
                }
                else if (child.Term.Name == "function body")
                {
                    startToken = child.ChildNodes[2].Token; // ')' symbol
                    endToken = child.ChildNodes[4].Token;   // 'end' keyword

                    //Offset the outline by 1 so we don't hide the ')' symbol.
                    startOffset = 1;
                }

                if (startToken != null && endToken != null)
                {
                    if (startToken.Location.Line != endToken.Location.Line)
                    {
                        var region = new HiddenRegion();
                        var span = new TextSpan();

                        span.iStartLine = startToken.Location.Line;
                        span.iStartIndex = startToken.Location.Column + startOffset;

                        span.iEndLine = endToken.Location.Line;
                        span.iEndIndex = endToken.Location.Column + endToken.Length;
                        region.Span = span;

                        regions.Add(region);
                    }
                }
                else
                {
                    //NOTE: This should be called for all children, but I'm running into a bug in which
                    // nested hidden regions screws up rendering for ALL hidden regions =(
                    FindHiddenRegions(child, ref regions);
                }
            }
        }

        public static List<BraceMatch> GetMatchingBraces(TokenList tokens)
        {
            var matches = new List<BraceMatch>();

        //    /*TokenList braces = tokens.Where<>;
        //    foreach (Token brace in braces)
        //    {
        //        TextSpan openBrace = new TextSpan();
        //        openBrace.iStartLine = brace.Location.Line;
        //        openBrace.iStartIndex = brace.Location.Column;
        //        openBrace.iEndLine = brace.Location.Line;
        //        openBrace.iEndIndex = openBrace.iStartIndex + brace.Length;

        //        TextSpan closeBrace = new TextSpan();
        //        closeBrace.iStartLine = brace.OtherBrace.Location.Line;
        //        closeBrace.iStartIndex = brace.OtherBrace.Location.Column;
        //        closeBrace.iEndLine = brace.OtherBrace.Location.Line;
        //        closeBrace.iEndIndex = closeBrace.iStartIndex + brace.OtherBrace.Length;

        //        BraceMatch match = new BraceMatch(openBrace, closeBrace, 1);
                
        //        //Determine if priority needs to be higher
        //        foreach(BraceMatch prevMatch in matches)
        //        {    
        //            if(prevMatch.IsNestedMatch(match))
        //            {
        //               // match.Priority++;
        //            }
        //        }
                           
        //        matches.Add(match);
        //    }*/

            return matches;
        }

        public static List<MemberDefinition> GetMembers(ParseTreeNode root)
        {
            var members = new List<MemberDefinition>();
            FindMembers(root, ref members);
            return members;
        }

        static void FindMembers(Irony.Parsing.ParseTreeNode root, ref List<MemberDefinition> members)
        {
            if (root == null || root.ChildNodes == null)
                return;

            foreach (var child in root.ChildNodes)
            {
                string memberName = String.Empty;
                Irony.Parsing.Token startToken = null;
                Irony.Parsing.Token endToken = null;

                if (child.Term.Name == "named function")
                {
                    memberName = child.ChildNodes[1].ChildNodes[0].Token.Text;
                    memberName += "(" + GetParListAsString(child.ChildNodes[2].ChildNodes[1]) + ")";


                    startToken = child.ChildNodes[0].Token; // 'function' symbol
                    endToken = child.ChildNodes[2].ChildNodes[4].Token;   // 'end' symbol
                }

                if (startToken != null && endToken != null)
                {
                    var member = new MemberDefinition();
                    var span = new TextSpan();

                    span.iStartLine = startToken.Location.Line;
                    span.iStartIndex = startToken.Location.Column;

                    span.iEndLine = endToken.Location.Line;
                    span.iEndIndex = endToken.Location.Column + endToken.Length;
                    member.Span = span;
                    member.Name = memberName;
                    member.IconIndex = (int)IconImageIndex.Method + (int)IconImageIndex.AccessPublic;

                    members.Add(member);
                }

                FindMembers(child, ref members);
            }
        }

        static string GetParListAsString(Irony.Parsing.ParseTreeNode root)
        {
            string parameterList = string.Empty;
            GetParListAsString(root, ref parameterList);
            return parameterList;
        }

        static void GetParListAsString(Irony.Parsing.ParseTreeNode root, ref string parameterList)
        {
            foreach (var child in root.ChildNodes)
            {
                var token = child.Token;
                if(token != null)
                {
                    if (parameterList != string.Empty)
                        parameterList += ", " + token.Text;
                    else
                        parameterList += token.Text;
                }

                GetParListAsString(child, ref parameterList);
            }
        }
    }
}
